//规定单链表里的元素
type element<T> = {
    value: T,
    next: element<T>|never;
}
//约束单链表类
interface Linked<T>{
    head: element<T> | never;
    length: number;
    //在尾部添加元素
    push(value: T): element<T>;
    //在某一位置插入元素
    insert(value: T, index: number): element<T>
    //判断链表是否为空
    isEmpty(): boolean;
    //返回链表中特定位置的元素
    getElementAt(index: number): element<T>;
    //返回链表中特定元素的位置
    indexOf(value: T): element<T> | number;
    //从链表中移除某个元素
    remove(value: T): boolean;
    //从链表中移除某一位置的元素
    removeAt(index: number): boolean
    //返回链表长度
    size(): number;
}
class LinkedList<T> implements Linked<T>{
    head: element<T> | never = null;
    length: number = 0;
    constructor(...value:T[]) {
        for (let index = 0; index < value.length; index++){
            this.push(value[index])
        }
    };

    protected createNode(value: T): element<T> {
        return {
            value,
            next:null
        }
    };

    protected isBorder(index: number) {
        if (this.length <= index || index < 0) throw new Error('链表越界')
    }

    push(value: T): element<T> {
        const newNode: element<T> = this.createNode(value)
        if (this.length==0) {
            this.head = newNode
        } else {
            let Node: element<T> = this.head;
            while (Node.next) {
                Node = Node.next
            }
            Node.next = newNode
        }
        this.length++
        return newNode
    }

    insert(value: T, index: number): element<T>{
        this.isBorder(index);
        const newNode: element<T> = this.createNode(value);
        let beforeNode: element<T>;
        let laterNode: element<T>;
        if (index == 0) {
            newNode.next = this.head
            this.head = newNode;
            this.length++
        } else {
            for (let i = 0; i < index; i++) {  //0 1
                if (i == 0) {
                    beforeNode = this.head;
                } else {
                    beforeNode = beforeNode.next
                }
                laterNode = beforeNode.next
            }
            newNode.next = laterNode
            beforeNode.next = newNode
            this.length++
        }
        return newNode
    }

    getElementAt(index: number): element<T>{
        this.isBorder(index)
        let current: element<T>=this.head;
        for (let i = 0; i < index;i++){
            current = current.next
        }
        return current
    }

    indexOf(value: T):number {
        let node: element<T>=this.head
        for (let index = 0; index < this.length && node != null;index++){
            node = this.getElementAt(index);
            if (node.value == value)return index
        }
        return -1
    }

    remove(value: T): boolean{
        let index: number = this.indexOf(value)
        if (index == -1) return false;
        this.removeAt(index)
    }

    removeAt(index: number): boolean {
        this.isBorder(index)
        let beforeNode: element<T>;
        let laterNode: element<T>;
        if (index == 0) {
            this.head = this.head.next;
            this.length--
            return true
        } else {
            for (let i = 0; i < index; i++) {
                if (i == 0) {
                    beforeNode = this.head;
                } else {
                    beforeNode = beforeNode.next
                }
                laterNode = beforeNode.next
            }
            beforeNode.next = laterNode.next
            this.length--
            return true
        }
    }

    size(): number{
        return this.length
    }

    isEmpty(): boolean {
        if (this.length) return false
        return true
    }
}
export default LinkedList
